﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Diagnostics;
using System.IO;
using AxShockwaveFlashObjects;
using CaptchaForm.CaptchaService;

namespace CaptchaForm
{
    public partial class MainForm : Form
    {
        public TimeSpan _enterTimeout = TimeSpan.FromSeconds(30);
        private int _counter = 0;
        private bool _typed = true;
        private string _text;
        private TimeSpan _timeRemaining;
        private Captcha _captcha;
        private Action _operation;
        private bool _operationIsRunning = false;

        public MainForm()
        {
            _operation = GetNext;
            InitializeComponent();
        }

        private void ShowCaptchaInternal()
        {
            if (_captcha != null)
            {
                if (_captcha.Image != null)
                {
                    using (var stream = new MemoryStream(_captcha.Image))
                        ShowCaptchaInternal(new Bitmap(stream));
                }
                else
                {
                    ShowCaptchaInternal(_captcha.FleshUrl);
                }
            }
        }
        private void ShowCaptchaInternal(Uri flashUri)
        {
            panel.SuspendLayout();
            PictureBox.Visible = false;
            AxShockwaveFlash.Visible = true;
            AxShockwaveFlash.Movie = flashUri.ToString();
            panel.ResumeLayout();
            _timeRemaining = _enterTimeout;
            lblRemainig.Text = string.Format("{0:ss}", _timeRemaining);
            if (activateFormToolStripMenuItem.Checked)
                Activate();
        }
        private void ShowCaptchaInternal(Bitmap captcha)
        {
            panel.SuspendLayout();
            PictureBox.Visible = true;
            AxShockwaveFlash.Visible = false;
            PictureBox.Image = captcha;
            panel.ResumeLayout();
            _timeRemaining = _enterTimeout;
            lblRemainig.Text = string.Format("{0:ss}", _timeRemaining);
            if (activateFormToolStripMenuItem.Checked)
                Activate();
        }

        private PictureBox PictureBox
        {
            get
            {
                var pb = panel.Controls.OfType<PictureBox>().FirstOrDefault();
                if (pb == null)
                {
                    pb = new PictureBox { Dock = DockStyle.Fill };
                    panel.Controls.Add(pb);
                }
                return pb;
            }
        }
        private AxShockwaveFlash AxShockwaveFlash
        {
            get
            {
                var flash = panel.Controls.OfType<AxShockwaveFlash>().FirstOrDefault();
                if (flash == null)
                {
                    flash = new AxShockwaveFlash { Dock = DockStyle.Fill };
                    panel.Controls.Add(flash);
                }
                return flash;
            }
        }

        private void Return()
        {
            if (_typed == false)
            {
                _counter++;
                lblCaptchaCount.Text = _counter.ToString();
                _text = txt.Text;
                AxShockwaveFlash.Visible = false;
                PictureBox.Visible = false;
                _typed = true;
            }
            txt.Text = string.Empty;
        }

        #region Operations
        private void RunOperation()
        {
            if (_operationIsRunning == false && _operation != null)
            {
                _operationIsRunning = true;
                ThreadPool.QueueUserWorkItem(state =>
                {
                    try
                    {
                        _operation();
                        Invoke(new Action(() => Text = "Please type a text on the picture and press enter"));
                    }
                    catch (Exception e)
                    {
                        Invoke(new Action(() => Text = e.Message));
                    }
                    finally
                    {
                        _operationIsRunning = false;
                    }
                });
            }
        }

        private void GetNext()
        {
            using (var client = new DistributedCaptchaServiceClient())
            {
                _captcha = client.GetNext();
                if (_captcha != null)
                {
                    _typed = false;
                    Invoke(new Action(ShowCaptchaInternal));
                    _operation = CheckTextTyped;
                }
            }
        }

        private void CheckTextTyped()
        {
            if (_typed)
                _operation = SendResult;
        }

        private void SendResult()
        {
            using (var client = new DistributedCaptchaServiceClient())
            {
                client.Result(_captcha.ID, _text);
            }
            _operation = GetNext;
        } 
        #endregion

        #region Events
        private void txt_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
                Return();
            else
                _timeRemaining = _enterTimeout;
        }

        private void CaptchaForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                if (_typed == false)
                {
                    using (var client = new DistributedCaptchaServiceClient())
                        client.Result(_captcha.ID, _text);
                }
            }
            catch
            {
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            RunOperation();

            if (_typed == false)
            {
                _timeRemaining -= TimeSpan.FromSeconds(1);
                if (_timeRemaining > TimeSpan.Zero)
                    lblRemainig.Text = string.Format("{0:ss}", _timeRemaining);
                else
                    Return();
            }
        }

        private void sec3toolStripMenuItem_Click(object sender, EventArgs e)
        {
            SetupEnterTimeout(sender, 3.0);
        }
        private void sec5ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SetupEnterTimeout(sender, 5.0);
        }
        private void sec10ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SetupEnterTimeout(sender, 10.0);
        }
        private void sec30ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SetupEnterTimeout(sender, 30.0);
        }
        private void SetupEnterTimeout(object sender, double seconds)
        {
            foreach (ToolStripMenuItem item in timeEnterToolStripMenuItem.DropDownItems)
                if (item.Checked && item != sender)
                    item.Checked = false;
            _enterTimeout = _timeRemaining = TimeSpan.FromSeconds(seconds);
        } 
        #endregion
    }
}
